package hbasecli.type;

import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.stereotype.Component;

@Component
public class DataTypes {

    private static final Logger log = LoggerFactory.getLogger(DataTypes.class);

    private final ConcurrentHashMap<String, DataType> map = new ConcurrentHashMap<>();

    @SuppressWarnings("unused")
    @PostConstruct
    private void init() {

        HexDataType hexDataType = new HexDataType();
        map.put(hexDataType.name(), hexDataType);

        UTF8DataType utf8DataType = new UTF8DataType();
        map.put(utf8DataType.name(), utf8DataType);

        ShortDataType shortDataType = new ShortDataType();
        map.put(shortDataType.name(), shortDataType);

        IntDataType intDataType = new IntDataType();
        map.put(intDataType.name(), intDataType);

        LongDataType longDataType = new LongDataType();
        map.put(longDataType.name(), longDataType);

        BooleanDataType booleanDataType = new BooleanDataType();
        map.put(booleanDataType.name(), booleanDataType);

        FloatDataType floatDataType = new FloatDataType();
        map.put(floatDataType.name(), floatDataType);

        DoubleDataType doubleDataType = new DoubleDataType();
        map.put(doubleDataType.name(), doubleDataType);

        BigDecimalDataType bigDecimalDataType = new BigDecimalDataType();
        map.put(bigDecimalDataType.name(), bigDecimalDataType);

        for (DataType dataType : SpringFactoriesLoader.loadFactories(DataType.class, null)) {
            log.info("Spring SPI load '{}' DataType", dataType.name());
            map.put(dataType.name(), dataType);
        }

        for (DataType dataType : ServiceLoader.load(DataType.class)) {
            log.info("Java SPI load '{}' DataType", dataType.name());
            map.put(dataType.name(), dataType);
        }
    }

    public DataType get(String name) {
        if (name == null) {
            return getDefault();
        }
        return map.getOrDefault(name, getDefault());
    }

    public List<String> list() {
        return new ArrayList<>(map.keySet());
    }

    public DataType getDefault() {
        return map.get("Hex");
    }

    public UTF8DataType getUTF8() {
        return (UTF8DataType) map.get("UTF-8");
    }

}
